package com.itstudio.portal.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itstudio.portal.entity.RestResponse;
import com.itstudio.portal.entity.UserNews;
import com.itstudio.portal.entity.dto.NewsAddDto;
import com.itstudio.portal.entity.vo.NewsListPageVo;
import com.itstudio.portal.entity.vo.NewsListVo;
import com.itstudio.portal.enums.HttpCodeEnum;
import com.itstudio.portal.mapper.NewsMapper;
import com.itstudio.portal.entity.News;
import com.itstudio.portal.mapper.UserNewsMapper;
import com.itstudio.portal.service.NewsService;
import com.itstudio.portal.utils.BeanCopyUtil;
import com.itstudio.portal.utils.Const;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * (News)表服务实现类
 *
 * @author feng
 * @since 2024-12-13 21:39:21
 */
@Service("newsService")
public class NewsServiceImpl extends ServiceImpl<NewsMapper, News> implements NewsService {

    @Resource
    UserNewsMapper userNewsMapper;

    @Resource
    RedisTemplate redisTemplate;

    @Override
    public RestResponse getList(Integer pageNum, Integer pageSize, Long id) {
        List<News> newsList = null;
        List<NewsListVo> newsListVos = new ArrayList<>();
        LambdaQueryWrapper<News> newsWrapper = new LambdaQueryWrapper<>();
        newsWrapper.orderByDesc(News::getCreateTime);
        Page page = new Page(pageNum, pageSize);
        if(id == null){
            page(page, newsWrapper);
            newsList = page.getRecords();
        }else {
            LambdaQueryWrapper<UserNews> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserNews::getUserId, id);
            List<UserNews> userNews = userNewsMapper.selectList(wrapper);
            if(!userNews.isEmpty() && userNews.size() > 0){
                List<Long> newsIds = userNews.stream().map(wn -> wn.getNewsId()).collect(Collectors.toList());
                newsWrapper.in(News::getId, newsIds);
                page(page, newsWrapper);
            }
            newsList = page.getRecords();
            newsList.stream()
                    .map(news -> {
                        Integer viewCount = (Integer) redisTemplate.opsForHash().get(Const.News_VIEW_COUNT_KEY, news.getId().toString());
                        if(viewCount != null)
                            news.setViewCount(viewCount.longValue());
                        return news;
                    }).collect(Collectors.toList());
        }
        if(!newsList.isEmpty())
            newsListVos = BeanCopyUtil.classListVo(newsList, NewsListVo.class);
        return RestResponse.success(new NewsListPageVo(newsListVos, page.getTotal()));
    }

    @Transactional
    @Override
    public RestResponse addNews(NewsAddDto newsAdd) {
        if(newsAdd.getUid() == null){
            return RestResponse.failure(HttpCodeEnum.USER_ID_NOT_NULL);
        }
        if(!StringUtils.hasText(newsAdd.getTitle())){
            return RestResponse.failure(HttpCodeEnum.NEWS_TITLE_NOT_NULL);
        }
        if(!StringUtils.hasText(newsAdd.getContent())){
            return RestResponse.failure(HttpCodeEnum.NEWS_CONTENT_NOT_NULL);
        }
        News news = BeanCopyUtil.classVo(newsAdd, News.class);
        getBaseMapper().AUTO_INCREMENT();
        save(news);
        userNewsMapper.insert(new UserNews(newsAdd.getUid(), news.getId()));
        redisTemplate.opsForHash().put(Const.News_VIEW_COUNT_KEY, news.getId().toString(), 0);
        return RestResponse.success();
    }

    @Override
    public RestResponse updateNews(NewsAddDto newsAdd) {
        if(newsAdd.getId() == null){
            return RestResponse.failure(HttpCodeEnum.NEWS_ID_NOT_NULL);
        }
        if(!StringUtils.hasText(newsAdd.getTitle())){
            return RestResponse.failure(HttpCodeEnum.NEWS_TITLE_NOT_NULL);
        }
        if(!StringUtils.hasText(newsAdd.getContent())){
            return RestResponse.failure(HttpCodeEnum.NEWS_CONTENT_NOT_NULL);
        }
        News news = BeanCopyUtil.classVo(newsAdd, News.class);
        boolean b = updateById(news);
        if(b)
            return RestResponse.success();
        return RestResponse.failure(HttpCodeEnum.NEWS_UPDATE_FAILURE);
    }

    @Transactional
    @Override
    public RestResponse deleteNews(Long id) {
        removeById(id);
        LambdaQueryWrapper<UserNews> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserNews::getNewsId, id);
        userNewsMapper.delete(wrapper);
        redisTemplate.opsForHash().delete(Const.News_VIEW_COUNT_KEY, id.toString());
        return RestResponse.success();
    }

    @Override
    public RestResponse getNewsById(Long id) {
        LambdaQueryWrapper<News> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(News::getId, id);
        News news = getOne(wrapper);
        if(Objects.nonNull(news)){
            Integer viewCount = (Integer) redisTemplate.opsForHash().get(Const.News_VIEW_COUNT_KEY, news.getId().toString());
            if(viewCount != null)
                news.setViewCount(viewCount.longValue());
        }
        NewsListVo newsList = BeanCopyUtil.classVo(news, NewsListVo.class);
        return RestResponse.success(newsList);
    }

    @Override
    public RestResponse updateView(Long id) {
        redisTemplate.opsForHash().increment(Const.News_VIEW_COUNT_KEY, id.toString(), 1);
        return RestResponse.success();
    }
}

